﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using BestTrader.Cms.Core;
using BestTrader.Cms.Core.Helper;
using BestTrader.Cms.Core.Options;
using BestTrader.Cms.RmmfSoftService;
using BestTrader.Cms.RmmfSoftServices.Models;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;

namespace BestTrader.Cms.RmmfSoftServices
{
    /// <summary>
    /// 管理 出入金
    /// </summary>
    public class RmmfSoftCashService
    {
        #region 1. 初始化
        protected RmmsoftOption _options;

        public RmmfSoftCashService(IOptionsSnapshot<RmmsoftOption> options)
        {
            _options = options.Get("RMMSOFT");
            if (_options == null)
            {
                throw new ArgumentNullException(nameof(RmmsoftOption));
            }
        }
        #endregion

        #region 2. 出金入金

        #region 2.1 进行出金入金

        /// <summary>
        /// 进行出金入金
        /// </summary>
        /// <param name="accountId">账户ID</param>
        /// <param name="cashState">类型
        ///     1:现金汇入
        ///     2:现金汇出
        ///     3:在途
        ///     4:转汇
        /// </param>
        /// <param name="amount">数量</param>
        /// <param name="currencyCode">币种</param>
        /// <param name="remark">说明</param>
        /// <returns></returns>
        public int AddCashChange(int accountId, int cashState, decimal amount, string currencyCode, string remark)
        {
            // 创建 HTTP 绑定对象
            var binding = new BasicHttpBinding();
            //设置最大传输接受数量
            binding.MaxReceivedMessageSize = 2147483647;
            // 根据 WebService 的 URL 构建终端点对象
            var endpoint = new EndpointAddress(_options.BaseUrl);
            // 创建调用接口的工厂，注意这里泛型只能传入接口 添加服务引用时生成的 webservice的接口 一般是 (XXXSoap)
            var factory = new ChannelFactory<WebServiceAPISoap>(binding, endpoint);
            // 从工厂获取具体的调用实例
            var callClient = factory.CreateChannel();
            //调用的对应webservice 服务类的函数生成对应的请求类Body (一般是webservice 中对应的方法+RequestBody  如GetInfoListRequestBody)
            AddCashChangeRequestBody body = new AddCashChangeRequestBody();
            //以下是为该请求body添加对应的参数（就是调用webService中对应的方法的参数）
            body.accountId = accountId;
            body.cashState = cashState;
            body.amount = amount;
            body.currencyCode = currencyCode;
            body.remark = remark;

            //获取请求对象 （一般是webservice 中对应的方法+tRequest  如GetInfoListRequest）
            var request = new AddCashChangeRequest(body);
            //发送请求
            var v = callClient.AddCashChangeAsync(request);
            //异步等待
            v.Wait();

            return v.Result.Body.AddCashChangeResult;
        }

        /// <summary>
        /// 2.2 查询账户资金信息
        /// </summary>
        /// <param name="accountName">账户名称</param>
        /// <returns>json
        ///                 AccountName	String	账户名称
        ///                 BuyingPower double 可用资金
        ///                 CashInOut double 现金存取
        ///                 Credit double 信用额度
        ///                 NLV double 平仓权益
        ///                 LUC double 冻结资产
        ///                 TotalMargin double 总保证金
        ///                 NLV_RMB double 平仓权益（RMB）
        ///                 Currency String  该账户的结算货币
        /// </returns>
        public RealTimeAssetOutput GetRealTimeAsset(string userName)
        {
            // 创建 HTTP 绑定对象
            var binding = new BasicHttpBinding();
            //设置最大传输接受数量
            binding.MaxReceivedMessageSize = 2147483647;
            // 根据 WebService 的 URL 构建终端点对象
            var endpoint = new EndpointAddress(_options.BaseUrl);
            // 创建调用接口的工厂，注意这里泛型只能传入接口 添加服务引用时生成的 webservice的接口 一般是 (XXXSoap)
            var factory = new ChannelFactory<WebServiceAPISoap>(binding, endpoint);
            // 从工厂获取具体的调用实例
            var callClient = factory.CreateChannel();
            //调用的对应webservice 服务类的函数生成对应的请求类Body (一般是webservice 中对应的方法+RequestBody  如GetInfoListRequestBody)
            var body = new GetRealTimeAssetRequestBody();
            //以下是为该请求body添加对应的参数（就是调用webService中对应的方法的参数）
            body.accountName = $"{userName}01";

            //获取请求对象 （一般是webservice 中对应的方法+tRequest  如GetInfoListRequest）
            var request = new GetRealTimeAssetRequest(body);
            //发送请求
            var v = callClient.GetRealTimeAssetAsync(request);
            //异步等待
            v.Wait();
            //获取数据
            var result = JsonConvert.DeserializeObject<RealTimeAssetOutput>(v.Result.Body.GetRealTimeAssetResult);

            return result;
        }

        /// <summary>
        /// 2.3 出入金（出金资金验证）
        /// </summary>
        /// <param name="accountName">账户名称</param>
        /// <param name="amount">金额</param>
        /// <param name="cashState">1：入金 2：出金</param>
        /// <param name="remark">银行卡姓名+卡号+银行名称+省份+市。字段间用逗号（，）分隔</param>
        /// <returns></returns>
        public CashChangeVerifyAssetOutput AddCashChangeVerifyAsset(string accountName, double amount, short cashState, string remark)
        {
            // 创建 HTTP 绑定对象
            var binding = new BasicHttpBinding();
            //设置最大传输接受数量
            binding.MaxReceivedMessageSize = 2147483647;
            // 根据 WebService 的 URL 构建终端点对象
            var endpoint = new EndpointAddress(_options.BaseUrl);
            // 创建调用接口的工厂，注意这里泛型只能传入接口 添加服务引用时生成的 webservice的接口 一般是 (XXXSoap)
            var factory = new ChannelFactory<WebServiceAPISoap>(binding, endpoint);
            // 从工厂获取具体的调用实例
            var callClient = factory.CreateChannel();
            //调用的对应webservice 服务类的函数生成对应的请求类Body (一般是webservice 中对应的方法+RequestBody  如GetInfoListRequestBody)
            var body = new AddCashChangeVerifyAssetRequestBody();
            //以下是为该请求body添加对应的参数（就是调用webService中对应的方法的参数）
            body.accountName = accountName;
            body.amount = amount;
            body.cashState = cashState;
            body.remark = remark;

            //获取请求对象 （一般是webservice 中对应的方法+tRequest  如GetInfoListRequest）
            var request = new AddCashChangeVerifyAssetRequest(body);
            //发送请求
            var v = callClient.AddCashChangeVerifyAssetAsync(request);
            //异步等待
            v.Wait();
            //获取数据
            var result = JsonConvert.DeserializeObject<CashChangeVerifyAssetOutput>(v.Result.Body.AddCashChangeVerifyAssetResult);

            return result;
        }

        #endregion

        #endregion

        #region 3. 手续费

        #region 3.1 账户手续费查询
        /// <summary>
        /// 3.1 账户手续费查询
        /// </summary>
        /// <param name="accountName"></param>
        /// <returns></returns>
        public List<FeeRulesByAccountNameOutput> GetFeeRulesByAccountName(string userName)
        {
            // 创建 HTTP 绑定对象
            var binding = new BasicHttpBinding();
            //设置最大传输接受数量
            binding.MaxReceivedMessageSize = 2147483647;
            // 根据 WebService 的 URL 构建终端点对象
            var endpoint = new EndpointAddress(_options.BaseUrl);
            // 创建调用接口的工厂，注意这里泛型只能传入接口 添加服务引用时生成的 webservice的接口 一般是 (XXXSoap)
            var factory = new ChannelFactory<WebServiceAPISoap>(binding, endpoint);
            // 从工厂获取具体的调用实例
            var callClient = factory.CreateChannel();
            //调用的对应webservice 服务类的函数生成对应的请求类Body (一般是webservice 中对应的方法+RequestBody  如GetInfoListRequestBody)
            var body = new GetFeeRulesByAccountNameRequestBody();
            //以下是为该请求body添加对应的参数（就是调用webService中对应的方法的参数）
            body.accountName = $"{userName}01";

            //获取请求对象 （一般是webservice 中对应的方法+tRequest  如GetInfoListRequest）
            var request = new GetFeeRulesByAccountNameRequest(body);
            //发送请求
            var v = callClient.GetFeeRulesByAccountNameAsync(request);
            //异步等待
            v.Wait();
            //获取数据
            var result = JsonConvert.DeserializeObject<List<FeeRulesByAccountNameOutput>>(v.Result.Body.GetFeeRulesByAccountNameResult);

            return result;
        }

        #endregion

        #region 3.2 删除账户手续费
        /// <summary>
        /// 3.2 删除账户手续费
        /// </summary>
        /// <param name="fpDefinitionID">手续费ID</param>
        /// <param name="fpProduct_Kind">产品类型</param>
        /// <param name="fpAccountName">账户名</param>
        /// <param name="fpExchangeCode">账户名</param>
        /// <param name="fpProductCode">账户名</param>
        /// <returns></returns>
        public int DeleteFeeRuleByAccount(int fpDefinitionID, int fpProduct_Kind, string userName,string fpExchangeCode,string fpProductCode)
        {
            // 创建 HTTP 绑定对象
            var binding = new BasicHttpBinding();
            //设置最大传输接受数量
            binding.MaxReceivedMessageSize = 2147483647;
            // 根据 WebService 的 URL 构建终端点对象
            var endpoint = new EndpointAddress(_options.BaseUrl);
            // 创建调用接口的工厂，注意这里泛型只能传入接口 添加服务引用时生成的 webservice的接口 一般是 (XXXSoap)
            var factory = new ChannelFactory<WebServiceAPISoap>(binding, endpoint);
            // 从工厂获取具体的调用实例
            var callClient = factory.CreateChannel();
            //调用的对应webservice 服务类的函数生成对应的请求类Body (一般是webservice 中对应的方法+RequestBody  如GetInfoListRequestBody)
            var body = new DeleteFeeRuleByAccountRequestBody();
            //以下是为该请求body添加对应的参数（就是调用webService中对应的方法的参数）
            body.fpDefinitionID = fpDefinitionID;
            body.fpProduct_Kind = fpProduct_Kind;
            body.fpAccountName = $"{userName}01";
            body.fpExchangeCode = fpExchangeCode;
            body.fpProductCode = fpProductCode;


            //获取请求对象 （一般是webservice 中对应的方法+tRequest  如GetInfoListRequest）
            var request = new DeleteFeeRuleByAccountRequest(body);
            //发送请求
            var v = callClient.DeleteFeeRuleByAccountAsync(request);
            //异步等待
            v.Wait();
            //获取数据
            return v.Result.Body.DeleteFeeRuleByAccountResult;
        }

        #endregion

        #region 3.3 账户手续费设置
        /// <summary>
        /// 3.3 账户手续费设置
        /// </summary>
        /// <param name="fpDefinitionID">手续费ID</param>
        /// <param name="fPFeeType">手续费类型</param>
        /// <param name="fPFeeRate">手续费</param>
        /// <param name="fpCurrencyCode">币种</param>
        /// <param name="fpAccountName">账户名</param>
        /// <param name="fpExchangeCode">交易所Code</param>
        /// <param name="fpProductCode">产品Code</param>
        /// <param name="fpProduct_Kind">产品类型</param>
        /// <returns></returns>
        public int InsertFeeRule(int fpDefinitionID, int fPFeeType, decimal fPFeeRate, string fpCurrencyCode, string userName, string fpExchangeCode, string fpProductCode, int fpProduct_Kind) {
            // 创建 HTTP 绑定对象
            var binding = new BasicHttpBinding();
            //设置最大传输接受数量
            binding.MaxReceivedMessageSize = 2147483647;
            // 根据 WebService 的 URL 构建终端点对象
            var endpoint = new EndpointAddress(_options.BaseUrl);
            // 创建调用接口的工厂，注意这里泛型只能传入接口 添加服务引用时生成的 webservice的接口 一般是 (XXXSoap)
            var factory = new ChannelFactory<WebServiceAPISoap>(binding, endpoint);
            // 从工厂获取具体的调用实例
            var callClient = factory.CreateChannel();
            //调用的对应webservice 服务类的函数生成对应的请求类Body (一般是webservice 中对应的方法+RequestBody  如GetInfoListRequestBody)
            var body = new InsertFeeRuleRequestBody();
            //以下是为该请求body添加对应的参数（就是调用webService中对应的方法的参数）
            body.fpDefinitionID = fpDefinitionID;
            body.fPFeeType = fPFeeType;
            body.fPFeeRate = fPFeeRate;
            body.fpCurrencyCode = fpCurrencyCode;
            body.fpAccountName = $"{userName}01";
            body.fpExchangeCode = fpExchangeCode;
            body.fpProductCode = fpProductCode;
            body.fpProduct_Kind = fpProduct_Kind;

            //获取请求对象 （一般是webservice 中对应的方法+tRequest  如GetInfoListRequest）
            var request = new InsertFeeRuleRequest(body);
            //发送请求
            var v = callClient.InsertFeeRuleAsync(request);
            //异步等待
            v.Wait();
            //获取数据
            return v.Result.Body.InsertFeeRuleResult;
        }
        #endregion

        #endregion

        #region 4. 历史出入金记录

        /// <summary>
        /// 4.1 历史出入金记录
        /// </summary>
        /// <param name="dtFrom">开始时间</param>
        /// <param name="dtTo">结束时间</param>
        /// <param name="accountId">用户帐号</param>
        /// <returns></returns>
        public List<CashChangesByAccountAndOrDateTimeOutput> GetCashChangesByAccountAndOrDateTime(DateTime dtFrom, DateTime dtTo, string accountId)
        {
            // 创建 HTTP 绑定对象
            var binding = new BasicHttpBinding();
            //设置最大传输接受数量
            binding.MaxReceivedMessageSize = 2147483647;
            // 根据 WebService 的 URL 构建终端点对象
            var endpoint = new EndpointAddress(_options.BaseUrl);
            // 创建调用接口的工厂，注意这里泛型只能传入接口 添加服务引用时生成的 webservice的接口 一般是 (XXXSoap)
            var factory = new ChannelFactory<WebServiceAPISoap>(binding, endpoint);
            // 从工厂获取具体的调用实例
            var callClient = factory.CreateChannel();
            //调用的对应webservice 服务类的函数生成对应的请求类Body (一般是webservice 中对应的方法+RequestBody  如GetInfoListRequestBody)
            var body = new GetCashChangesByAccountAndOrDateTimeRequestBody();
            //以下是为该请求body添加对应的参数（就是调用webService中对应的方法的参数）
            body.dtFrom = dtFrom;
            body.dtTo = dtTo;
            body.accountId = accountId;

            //获取请求对象 （一般是webservice 中对应的方法+tRequest  如GetInfoListRequest）
            var request = new GetCashChangesByAccountAndOrDateTimeRequest(body);
            //发送请求
            var v = callClient.GetCashChangesByAccountAndOrDateTimeAsync(request);
            //异步等待
            v.Wait();
            //获取数据
            var result = JsonConvert.DeserializeObject<List<CashChangesByAccountAndOrDateTimeOutput>>(v.Result.Body.GetCashChangesByAccountAndOrDateTimeResult);

            return result;
        }

        #endregion
    }
}
